﻿#include "ProjectModel.h" 
#include "Framework/Editor.h"
#include "File/FileUtils.h"
#include "Widgets/Windows/MessageBox.h"
#include "Asset/AssetSubsystem.h"

#include "ScriptCompiler/Compiler.h"
#include "ScriptCompiler/CompileResult.h"
#include "ScriptRuntime/ByteCode/ByteCodeFile.h"

#include "Platform/PlatformInterface.h"

#include "Path/Paths.h"

#include "Output/Console.h"
#include "Project/ProjectModelSubsystem.h"
#include "Project/ProjectViewModel.h"

#include "Framework/Editor.h"

static RProjectModel * GProjectModel=nullptr;

RProjectModel *RProjectModel::Get()
{
    return GProjectModel;
}

void RProjectModel::Initialize()
{
    GProjectModel=this;
    Super::Initialize();
}

void RProjectModel::Deinitialize()
{
    GProjectModel=nullptr;
    Super::Deinitialize();
}

void RProjectModel::FirstTimeInitializeObject()
{
    SubsystemManager=NewObject<RSubsystemManager>(this);

    Super::FirstTimeInitializeObject();

}

TOptional<CString> RProjectModel::CreateProject(
    const CString &ProjectName, const SPath &ProjectPath)
{
    if(ProjectName.IsEmpty())
    {
        return CString(U"项目名称不能为空");
    }

    if(ProjectPath.IsEmpty())
    {
        return CString(U"项目路径不能为空");
    }

    if(!ProjectPath.Exists())
    {
        return CString(U"项目文件夹不存在");
    }

    if(!ProjectPath.IsEmptyDirectory())
    {
        return CString(U"项目文件夹不是空的");
    }

    //create project setting file
    SPath ProjectSettingFilePath=ProjectPath / (ProjectName+GetProjectExtension());
    
    //just create a empty file
    {
        std::ofstream ProjectSettingFile(ProjectSettingFilePath.GetLowLevel());
        if (!ProjectSettingFile.is_open())
        {
            return CString(U"无法创建项目文件");
        }
    }


    //create a Asset folder
    SPath AssetFolder=ProjectPath / U"Asset";
    auto Error=SFileUtils::CreateDirectory(AssetFolder);
    if (!Error.IsEmpty())
    {
        return Error;
    }

    //create a Scripts folder project folder
    SPath ScriptsFolder=ProjectPath / U"Scripts";
    Error=SFileUtils::CreateDirectory(ScriptsFolder);
    if (!Error.IsEmpty())
    {
        return Error;
    }

    //create a Main.cs file under scripts
    SPath MainScriptFile=ScriptsFolder / U"Main.cs";
    {
        std::ofstream MainScriptFileStream(MainScriptFile.GetLowLevel());
        if (!MainScriptFileStream.is_open())
        {
            return CString(U"创建文件失败");
        }
             
        //write a default main script ,in c# language
        CString FileAsset=U"using Engine;\n\n";
        FileAsset+=U"namespace "+ProjectName+U"\n";
        FileAsset+=U"{\n";
        FileAsset+=U"    class Entry\n";
        FileAsset+=U"    {\n";
        FileAsset+=U"        static void Main()\n";
        FileAsset+=U"        {\n";
        FileAsset+=U"            RConsole.PrintLine(\"Hello World!\");\n";
        FileAsset+=U"            //创建一个空白的窗口\n";
        FileAsset+=U"            RWindow MainWindow = new RWindow();\n";
        FileAsset+=U"            MainWindow.SetWindowSize(800,600);\n";
        FileAsset+=U"            MainWindow.MoveToScreenCenter();\n";
        FileAsset+=U"            MainWindow.SetWindowTitle(\""+ProjectName+U"\");\n";
        FileAsset+=U"            MainWindow.Show();\n";
        FileAsset+=U"        }\n";
        FileAsset+=U"    }\n";
        FileAsset+=U"}\n";

        auto FileAsset8 = FileAsset.ToUtf8();
        MainScriptFileStream << (const char* )FileAsset8.Data();
    }


    //done
    return TOptional<CString>();
}



TOptional<CString> RProjectModel::OpenProject(const SPath &ProjectFolderPath)
{
    //先关闭当前项目
    if(CurrentProjectInfo.HasValue())
    {
        if(RProjectViewModel::IsInitialized())
        {
            RProjectViewModel::Get()->NotifyProjectClosed();
        }
        OnProjectClosed.Broadcast();
        SubsystemManager->DeinitializeSubsystems();
        CurrentProjectInfo.Reset();
    }


    if(!ProjectFolderPath.Exists())
    {
        return CString(U"Project folder not exists");
    }

    if(!ProjectFolderPath.IsDirectory())
    {
        return CString(U"Project folder is not a directory");
    }

    //make sure asset folder exists
    SPath AssetFolder=ProjectFolderPath / U"Asset";
    if(!AssetFolder.Exists())
    {
        return CString(U"Asset folder not found");
    }

    //find project setting file by extension
    auto ProjectSettingFiles=ProjectFolderPath.ListFiles().Filter([](const SPath& Path)
    {
        return Path.IsFileWithExtension(GetProjectExtension());
    });

    if(ProjectSettingFiles.Empty())
    {
        return CString(U"["+GetProjectExtension()+U"] file not found");
    }

    if(ProjectSettingFiles.Num()>1)
    {
        return CString(U"Multiple project setting files found, please delete redundant files");
    }

    SPath ProjectSettingFilePath=ProjectSettingFiles[0];

    //load project setting file
    //todo

    //save to history
    SProjectPathInfo NewProjectInfo;
    NewProjectInfo.Name=ProjectSettingFilePath.GetBaseFileName();
    NewProjectInfo.Path=ProjectFolderPath.ToString();
    

    CurrentProjectInfo=NewProjectInfo;
    REditor::Get()->AddHistoryProjectInfo(NewProjectInfo);

    //save to setting file
    REditor::Get()->SaveSetting();


    //register project package
    SAssetPackage ProjectAssetPackage;
    ProjectAssetPackage.Name=NewProjectInfo.Name;
    ProjectAssetPackage.Path=ProjectFolderPath.ToString();
    RAssetSubsystem::Get()->AddPackage(ProjectAssetPackage);

    //notify project opened
    SubsystemManager->InitializeSubsystems(RProjectModelSubsystem::StaticClass(),this);
    OnProjectOpened.Broadcast();
    if(RProjectViewModel::IsInitialized())
    {
        RProjectViewModel::Get()->NotifyProjectOpened();
    }

    return TOptional<CString>();
}

TOptional<SPath> RProjectModel::GetProjectDirectory() const
{
    if(CurrentProjectInfo.HasValue())
    {
        return SPath(CurrentProjectInfo->Path);
    }
    return TOptional<SPath>();
}

TOptional<SPath> RProjectModel::GetAssetDirectory() const
{
    if (CurrentProjectInfo.HasValue())
    {
        return SPath(CurrentProjectInfo->Path) / U"Asset";
    }
    return TOptional<SPath>();
}

TOptional<SAssetPackage> RProjectModel::GetAssetPackage() const
{
    if(CurrentProjectInfo.HasValue())
    {
        SAssetPackage ProjectAssetPackage;
        ProjectAssetPackage.Name=CurrentProjectInfo->Name;
        ProjectAssetPackage.Path=CurrentProjectInfo->Path;
        return ProjectAssetPackage;
    }
    return TOptional<SAssetPackage>();
}

TOptional<CString> RProjectModel::BuildProject()
{
    if(!CurrentProjectInfo.HasValue())
    {
        return CString(U"没有打开的项目，无法构建");
    }

    SPath ProjectDir=CurrentProjectInfo.GetValue().Path;

    return WH::CompileProjectScripts(ProjectDir);
}

// bool RProjectModel::LaunchProject(bool bDebugMode,uint32_t DebugPort)
// {
//     if(!CurrentProjectInfo.HasValue())
//     {
//         WH::PrintLine(U"没有打开的项目，无法启动");
//         return false;
//     }

//     //launch command
//     SPath BuildFolder=CurrentProjectInfo.GetValue().Path + U"/Build";
//     SPath ByteCodeFile=BuildFolder / U"ByteCode.bin";

//     CString PlatformFolderName;
//     switch(IPlatformInterface::GetPlatformInterface()->GetPlatform())
//     {
//         case EPlatform::Windows:
//         {
//             PlatformFolderName=U"Win64";
//         }
//         break;

//         case EPlatform::Linux:
//         {
//             PlatformFolderName=U"Linux";
//         }
//         break;

//         default:
//         {
//             assert(false);
//             return false;
//         }
//     }

//     CString CommandLine=
//         (SPaths::GetExecutablePath().Parent()
//         /U"ProjectTemplate"
//         /PlatformFolderName
//         /U"ScriptProjectTemplate.exe").ToString();

//     CommandLine+=U" RootFolder=";
//     CommandLine+=CurrentProjectInfo.GetValue().Path;

//     if(bDebugMode)
//     {
//         CommandLine+=U" DebugPort="+CString(DebugPort);
//     }

//     WH::PrintLine(U"创建进程");
//     WH::PrintLine(CommandLine);

//     int64_t ProcessID=IPlatformInterface::GetPlatformInterface()->CreateProcessWithoutBlock(
//         CommandLine
//         ,BuildFolder.ToString());

//     if(-1==ProcessID)
//     {
//         WH::PrintLine(U"创建进程失败");
//         return false;
//     }
//     WH::PrintLine(U"已创建项目进程["+CString(ProcessID)+U"]");
   
//     return true;
// }

CString RProjectModel::CreateLaunchCommand(bool bDebugMode, uint32_t DebugPort)
{
    assert(CurrentProjectInfo.HasValue() &&"没有打开的项目，无法启动" );
 
    //launch command
    SPath BuildFolder=CurrentProjectInfo.GetValue().Path + U"/Build";
    SPath ByteCodeFile=BuildFolder / U"ByteCode.bin";

    CString PlatformFolderName;
    switch(IPlatformInterface::GetPlatformInterface()->GetPlatform())
    {
        case EPlatform::Windows:
        {
            PlatformFolderName=U"Win64";
        }
        break;

        case EPlatform::Linux:
        {
            PlatformFolderName=U"Linux";
        }
        break;

        default:
        {
            assert(false);
            return false;
        }
    }

    CString CommandLine=
        (SPaths::GetExecutablePath().Parent()
        /U"ProjectTemplate"
        /PlatformFolderName
        /U"ScriptProjectTemplate.exe").ToString();

    CommandLine+=U" RootFolder=";
    CommandLine+=CurrentProjectInfo.GetValue().Path;

    if(bDebugMode)
    {
        CommandLine+=U" DebugPort="+CString(DebugPort);
    }

    return CommandLine;
}
